home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / file / managers / mc-3.2 / mc-3 / mc-3.2.1 / src / key.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-17  |  21.9 KB  |  973 lines

  1. /* Keyboard support routines.
  2.  
  3.    Copyright (C) 1994,1995 the Free Software Foundation.
  4.  
  5.    Written by: 1994, 1995 Miguel de Icaza.
  6.                1994, 1995 Janne Kukonlehto.
  7.            1995  Jakub Jelinek.
  8.    
  9.    This program is free software; you can redistribute it and/or modify
  10.    it under the terms of the GNU General Public License as published by
  11.    the Free Software Foundation; either version 2 of the License, or
  12.    (at your option) any later version.
  13.    
  14.    This program is distributed in the hope that it will be useful,
  15.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.    GNU General Public License for more details.
  18.  
  19.    You should have received a copy of the GNU General Public License
  20.    along with this program; if not, write to the Free Software
  21.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  22.  
  23. #include <config.h>
  24. #include <stdio.h>
  25. #include <sys/types.h>
  26. #include <string.h>
  27. #ifdef HAVE_UNISTD_H
  28. #   include <unistd.h>
  29. #endif
  30. #include <sys/types.h>        /* FD_ZERO et al */
  31. #include <sys/time.h>        /* struct timeval */
  32. #if IS_AIX
  33. #   include <sys/select.h>
  34. #endif
  35. #include "tty.h"
  36. #include <ctype.h>
  37. #include <errno.h>
  38. #include <malloc.h> 
  39. #include "util.h"        /* For xmalloc prototype */
  40. #include "mad.h"        /* The memory debugger */
  41. #include "global.h"
  42. #include "mouse.h"
  43. #include "key.h"
  44. #include "main.h"
  45. #include "file.h"
  46. #include "../vfs/vfs.h"
  47. #ifdef __linux__
  48. #  include <linux/termios.h> /* This is needed for TIOCLINUX */
  49. #endif
  50. #ifdef HAVE_TK
  51. #   include <tcl.h>
  52. #endif
  53.  
  54. /* "$Id: key.c,v 1.18 1995/02/21 19:06:13 miguel Exp $" */
  55.  
  56. /* This macros were stolen from gpm 0.15 */
  57. #define GET_TIME(tv) (gettimeofday(&tv, (struct timezone *)NULL))
  58. #define DIF_TIME(t1,t2) ((t2.tv_sec -t1.tv_sec) *1000+ \
  59.              (t2.tv_usec-t1.tv_usec)/1000)
  60.              
  61. /* timeout for old_esc_mode in usec */
  62. #define ESCMODE_TIMEOUT 1000000
  63.  
  64. int mou_auto_repeat = 100;
  65. int double_click_speed = 250;
  66. int old_esc_mode = 0;
  67.  
  68. int use_8th_bit_as_meta = 1;
  69.  
  70. #ifdef HAVE_XVIEW
  71. int xmouse_flag = 0;
  72. #endif
  73.  
  74. #ifndef HAVE_XVIEW
  75. typedef struct key_def {
  76.     char ch;            /* Holds the matching char code */
  77.     int code;            /* The code returned, valid if child == NULL */
  78.     struct key_def *next;
  79.     struct key_def *child;    /* sequence continuation */
  80.     int action;            /* optional action to be done. Now used only
  81.                                    to mark that we are just after the first
  82.                                    Escape */
  83. } key_def;
  84.  
  85. /* This holds all the key definitions */
  86. static key_def *keys = 0;
  87. #endif
  88.  
  89. static int input_fd;
  90. static fd_set select_set;
  91. static int disabled_channels = 0; /* Disable channels checking */
  92.  
  93. #ifndef HAVE_TK
  94. /* File descriptor monitoring add/remove routines */
  95. typedef struct SelectList {
  96.     int fd;
  97.     select_fn callback;
  98.     void *info;
  99.     struct SelectList *next;
  100. } SelectList;
  101.  
  102. SelectList *select_list = 0;
  103. #endif
  104.  
  105. int xgetch_second (void);
  106.  
  107. #ifdef HAVE_TK
  108. void add_select_channel (int fd, select_fn callback, void *info)
  109. {
  110.     Tcl_File handle;
  111.  
  112.     handle = Tcl_GetFile ((ClientData) fd, TCL_UNIX_FD);
  113.     Tcl_CreateFileHandler (handle, TCL_READABLE, (Tcl_FileProc *) callback, 0);
  114. }
  115.  
  116. void delete_select_channel (int fd)
  117. {
  118.     Tcl_File handle;
  119.  
  120.     handle = Tcl_GetFile ((ClientData) fd, TCL_UNIX_FD);
  121.     Tcl_DeleteFileHandler (handle);
  122.     Tcl_FreeFile (handle);
  123. }
  124. #else
  125. void add_select_channel (int fd, select_fn callback, void *info)
  126. {
  127.     SelectList *new;
  128.  
  129.     new = xmalloc (sizeof (SelectList), "add_select_channel");
  130.     new->fd = fd;
  131.     new->callback = callback;
  132.     new->info = info;
  133.     new->next = select_list;
  134.     select_list = new;
  135. }
  136.  
  137. void delete_select_channel (int fd)
  138. {
  139.     SelectList *p = select_list;
  140.     SelectList *prev = 0;
  141.     
  142.     while (p){
  143.     if (p->fd == fd){
  144.         if (prev)
  145.         prev->next = p->next;
  146.         else
  147.         select_list = p->next;
  148.         free (p);
  149.     }
  150.     prev = p;
  151.     }
  152. }
  153.  
  154. inline static int add_selects (fd_set *select_set)
  155. {
  156.     SelectList *p;
  157.     int        top_fd = 0;
  158.  
  159.     if (disabled_channels)
  160.     return 0;
  161.     
  162.     for (p = select_list; p; p = p->next){
  163.     FD_SET (p->fd, select_set);
  164.     if (p->fd > top_fd)
  165.         top_fd = p->fd;
  166.     }
  167.     return top_fd;
  168. }
  169.  
  170. static void check_selects (fd_set *select_set)
  171. {
  172.     SelectList *p;
  173.  
  174.     if (disabled_channels)
  175.     return;
  176.     
  177.     for (p = select_list; p; p = p->next)
  178.     if (FD_ISSET (p->fd, select_set))
  179.         (*p->callback)(p->fd, p->info);
  180. }
  181. #endif
  182.  
  183. void channels_down (void)
  184. {
  185.     disabled_channels ++;
  186. }
  187.  
  188. void channels_up (void)
  189. {
  190.     if (!disabled_channels)
  191.     fprintf (stderr,
  192.          "Error: channels_up called with disabled_channels = 0\n");
  193.     disabled_channels--;
  194. }
  195.  
  196. typedef struct {
  197.     int code;
  198.     char *seq;
  199.     int action;
  200. } key_define_t;
  201.  
  202. #ifndef HAVE_XVIEW
  203. key_define_t mc_bindings [] = {
  204.     { KEY_END,    ESC_STR ">", MCKEY_NOACTION },
  205.     { KEY_HOME,   ESC_STR "<", MCKEY_NOACTION },
  206.  
  207. #ifdef linux
  208.     /* Incredible, but many Linuxes still have old databases */
  209.     { KEY_IC,     ESC_STR "[2~", MCKEY_NOACTION },
  210. #endif
  211.     { 0, 0, MCKEY_NOACTION },
  212. };
  213.  
  214. /* Broken terminfo and termcap databases on xterminals */
  215. key_define_t xterm_key_defines [] = {
  216.     { KEY_F(1),   ESC_STR "[11~", MCKEY_NOACTION },
  217.     { KEY_F(2),   ESC_STR "[12~", MCKEY_NOACTION },
  218.     { KEY_F(3),   ESC_STR "[13~", MCKEY_NOACTION },
  219.     { KEY_F(4),   ESC_STR "[14~", MCKEY_NOACTION },
  220.     { KEY_F(5),   ESC_STR "[15~", MCKEY_NOACTION },
  221.     { KEY_F(6),   ESC_STR "[17~", MCKEY_NOACTION },
  222.     { KEY_F(7),   ESC_STR "[18~", MCKEY_NOACTION },
  223.     { KEY_F(8),   ESC_STR "[19~", MCKEY_NOACTION },
  224.     { KEY_F(9),   ESC_STR "[20~", MCKEY_NOACTION },
  225.     { KEY_F(10),  ESC_STR "[21~", MCKEY_NOACTION },
  226.     { 0, 0, MCKEY_NOACTION },
  227. };
  228.  
  229. key_define_t mc_default_keys [] = {
  230.     { ESC_CHAR,    ESC_STR, MCKEY_ESCAPE },
  231.     { ESC_CHAR, ESC_STR ESC_STR, MCKEY_NOACTION },
  232.     { 0, 0, MCKEY_NOACTION },
  233. };
  234. #endif
  235.  
  236. void define_sequences (key_define_t *kd)
  237. {
  238. #ifndef HAVE_XVIEW
  239.     int i;
  240.     
  241.     for (i = 0; kd [i].code; i++)
  242.     define_sequence(kd [i].code, kd [i].seq, kd [i].action);
  243. #endif    
  244. }
  245.  
  246. void init_key (void)
  247. {
  248. #ifndef HAVE_XVIEW
  249.     char *term = (char *) getenv ("TERM");
  250.     
  251.     /* This has to be the first define_sequence */
  252.     /* So, we can assume that the first keys member has ESC */
  253.     define_sequences (mc_default_keys);
  254.     
  255.     /* Terminfo on irix does not have some keys */
  256.     if ((!strncmp (term, "iris-ansi", 9)) || (!strncmp (term, "xterm", 5)))
  257.     define_sequences (xterm_key_defines);
  258.     
  259.     define_sequences (mc_bindings);
  260.     
  261. #ifdef HAVE_SLANG
  262.     input_fd = fileno (stdin);
  263. #endif
  264. #endif /* !HAVE_XVIEW */
  265. }
  266.  
  267. #ifndef HAVE_XVIEW
  268. void xmouse_get_event (Gpm_Event *ev)
  269. {
  270.     int btn;
  271.     static struct timeval tv1 = { 0, 0 }; /* Force first click as single */
  272.     static struct timeval tv2;
  273.     static int clicks;
  274.  
  275.     /* Decode Xterm mouse information to a GPM style event */
  276.  
  277.     /* Variable btn has following meaning: */
  278.     /* 0 = btn1 dn, 1 = btn2 dn, 2 = btn3 dn, 3 = btn up */
  279.     btn = xgetch () - 32;
  280.     
  281.     /* There seems to be no way of knowing which button was released */
  282.     /* So we assume all the buttons were released */
  283.  
  284.     if (btn == 3){
  285.         ev->type = GPM_UP | (GPM_SINGLE << clicks);
  286.         ev->buttons = 0;
  287.     GET_TIME (tv1);
  288.     clicks = 0;
  289.     } else {
  290.         ev->type = GPM_DOWN;
  291.     GET_TIME (tv2);
  292.     if (tv1.tv_sec && (DIF_TIME (tv1,tv2) < double_click_speed)){
  293.         clicks++;
  294.         clicks %= 3;
  295.     } else
  296.         clicks = 0;
  297.     
  298.         switch (btn) {
  299.     case 0:
  300.             ev->buttons |= GPM_B_LEFT;
  301.             break;
  302.     case 1:
  303.             ev->buttons |= GPM_B_MIDDLE;
  304.             break;
  305.     case 2:
  306.             ev->buttons |= GPM_B_RIGHT;
  307.             break;
  308.     default:
  309.             /* Nothing */
  310.             break;
  311.         }
  312.     }
  313.     /* Coordinates are 33-based */
  314.     /* Transform them to 1-based */
  315.     ev->x = xgetch () - 32;
  316.     ev->y = xgetch () - 32;
  317. }
  318.  
  319. static key_def *create_sequence (char *seq, int code, int action)
  320. {
  321.     key_def *base, *p, *attach;
  322.  
  323.     for (base = attach = NULL; *seq; seq++){
  324.     p = xmalloc (sizeof (key_def), "create_sequence");
  325.     if (!base) base = p;
  326.     if (attach) attach->child = p;
  327.     
  328.     p->ch   = *seq;
  329.     p->code = code;
  330.     p->child = p->next = NULL;
  331.     if (!seq[1])
  332.         p->action = action;
  333.     else
  334.         p->action = MCKEY_NOACTION;
  335.     attach = p;
  336.     }
  337.     return base;
  338. }
  339.  
  340. /* The maximum sequence length (32 + null terminator) */
  341. static int seq_buffer [33];
  342. static int *seq_append = 0;
  343.  
  344. static int push_char (int c)
  345. {
  346.     if (!seq_append)
  347.     seq_append = seq_buffer;
  348.     
  349.     if (seq_append == &(seq_buffer [sizeof (seq_buffer)-2]))
  350.     return 0;
  351.     *(seq_append++) = c;
  352.     *seq_append = 0;
  353.     return 1;
  354. }
  355. #endif /* !HAVE_XVIEW */
  356.  
  357. void define_sequence (int code, char *seq, int action)
  358. {
  359. #ifndef HAVE_XVIEW
  360.     key_def *base;
  361.  
  362.     if (strlen (seq) > sizeof (seq_buffer)-1)
  363.     return;
  364.     
  365.     for (base = keys; (base != 0) && *seq; ){
  366.     if (*seq == base->ch){
  367.         if (base->child == 0){
  368.         if (*(seq+1)){
  369.             base->child = create_sequence (seq+1, code, action);
  370.             return;
  371.         } else {
  372.             /* The sequence clashes */
  373.             return;
  374.         }
  375.         } else {
  376.         base = base->child;
  377.         seq++;
  378.         }
  379.     } else {
  380.         if (base->next)
  381.         base = base->next;
  382.         else {
  383.         base->next = create_sequence (seq, code, action);
  384.         return;
  385.         }
  386.     }
  387.     }
  388.     keys = create_sequence (seq, code, action);
  389. #endif    
  390. }
  391.  
  392. #ifndef HAVE_XVIEW
  393. static int *pending_keys;
  394. #endif
  395.  
  396. int correct_key_code (int c)
  397. {
  398.     /* This is needed on some OS that do not support ncurses and */
  399.     /* do some magic after read()ing the data */
  400.     if (c == '\r')
  401.     return '\n';
  402.  
  403. #ifdef IS_AIX
  404.     if (c == KEY_SCANCEL)
  405.     return '\t';
  406. #endif
  407.  
  408.     if (c == KEY_F(0))
  409.     return KEY_F(10);
  410.     
  411.     switch (c) {
  412.         case KEY_KP_ADD: c = alternate_plus_minus ? ALT('+') : '+'; break;
  413.         case KEY_KP_SUBTRACT: c = alternate_plus_minus ? ALT('-') : '-'; break;
  414.         case KEY_KP_MULTIPLY: c = alternate_plus_minus ? ALT('*') : '*'; break;
  415.     }
  416.  
  417.     return c;
  418. }
  419.  
  420. int get_key_code (int no_delay)
  421. {
  422. #ifndef HAVE_XVIEW
  423.     int c;
  424.     static key_def *this = NULL, *parent;
  425.     static struct timeval esctime = { -1, -1 };
  426.     static int lastnodelay = -1;
  427.     
  428.     if (no_delay != lastnodelay) {
  429.         this = NULL;
  430.         lastnodelay = no_delay;
  431.     }
  432.  
  433.  pend_send:
  434.     if (pending_keys){
  435.     int d = *pending_keys++;
  436.  check_pend:
  437.     if (!*pending_keys){
  438.         pending_keys = 0;
  439.         seq_append = 0;
  440.     }
  441.     if (d == ESC_CHAR && pending_keys){
  442.         d = ALT(*pending_keys++);
  443.         goto check_pend;
  444.     }
  445.     if ((d & 0x80) && use_8th_bit_as_meta)
  446.         d = ALT(d & 0x7f);
  447.     this = NULL;
  448.     return correct_key_code (d);
  449.     }
  450.  
  451.  nodelay_try_again:
  452.     if (no_delay) {
  453. #ifdef BUGGY_CURSES
  454.         wtimeout(stdscr, 500);
  455. #else
  456.         nodelay (stdscr, TRUE);
  457. #endif
  458.     }
  459.     c = xgetch ();
  460.     if (no_delay) {
  461. #ifdef BUGGY_CURSES
  462.         notimeout (stdscr, TRUE);
  463. #else
  464.         nodelay (stdscr, FALSE);
  465. #endif
  466.         if (c == ERR) {
  467.             if (this != NULL && parent != NULL && 
  468.                 parent->action == MCKEY_ESCAPE && old_esc_mode) {
  469.                 struct timeval current, timeout;
  470.                 
  471.                 if (esctime.tv_sec == -1)
  472.                     return ERR;
  473.                 GET_TIME (current);
  474.                 timeout.tv_sec = ESCMODE_TIMEOUT / 1000000 + esctime.tv_sec;
  475.                 timeout.tv_usec = ESCMODE_TIMEOUT % 1000000 + esctime.tv_usec;
  476.                 if (timeout.tv_usec > 1000000) {
  477.                     timeout.tv_usec -= 1000000;
  478.                     timeout.tv_sec++;
  479.                 }
  480.                 if (current.tv_sec < timeout.tv_sec)
  481.                     return ERR;
  482.                 if (current.tv_sec == timeout.tv_sec && 
  483.                     current.tv_usec < timeout.tv_usec)
  484.                     return ERR;
  485.                 this = NULL;
  486.         pending_keys = seq_append = NULL;
  487.         return ESC_CHAR;
  488.             }
  489.             return ERR;
  490.         }
  491.     } else if (c == ERR){
  492.     /* Maybe we got an incomplete match.
  493.        This we do only in delay mode, since otherwise
  494.        xgetch can return ERR at any time. */
  495.     if (seq_append) {
  496.         pending_keys = seq_buffer;
  497.         goto pend_send;
  498.     }
  499.     this = NULL;
  500.     return ERR;
  501.     }
  502.     
  503.     /* Search the key on the root */
  504.     if (!no_delay || this == NULL) {
  505.         this = keys;
  506.         parent = NULL;
  507.  
  508.         if ((c & 0x80) && use_8th_bit_as_meta) {
  509.             c &= ~0x7f;
  510.  
  511.         /* The first sequence defined starts with esc */
  512.         parent = keys;
  513.         this = keys->child;
  514.         }
  515.     }
  516.     while (this){
  517.     if (c == this->ch){
  518.         if (this->child){
  519.         if (!push_char (c)){
  520.             pending_keys = seq_buffer;
  521.             goto pend_send;
  522.         }
  523.         parent = this;
  524.         this = this->child;
  525.         if (parent->action == MCKEY_ESCAPE && old_esc_mode) {
  526.             if (no_delay) {
  527.                 GET_TIME (esctime);
  528.                 if (this == NULL) {
  529.                     /* Shouldn't happen */
  530.                     fprintf (stderr, "Internal error\n");
  531.                     exit (1);
  532.                 }
  533.                 goto nodelay_try_again;
  534.             }
  535.             esctime.tv_sec = -1;
  536.             c = xgetch_second ();
  537.             if (c == ERR) {
  538.                 pending_keys = seq_append = NULL;
  539.                 this = NULL;
  540.                 return ESC_CHAR;
  541.             }
  542.         } else {
  543.             if (no_delay)
  544.                 goto nodelay_try_again;
  545.             c = xgetch ();
  546.         }
  547.         } else {
  548.         /* We got a complete match, return and reset search */
  549.         int code;
  550.         
  551.         pending_keys = seq_append = NULL;
  552.         code = this->code;
  553.         this = NULL;
  554.         return correct_key_code (code);
  555.         }
  556.     } else {
  557.         if (this->next)
  558.         this = this->next;
  559.         else {
  560.             if (parent != NULL && parent->action == MCKEY_ESCAPE) {
  561.                 /* This is just to save a lot of define_sequences */
  562.                 if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')
  563.             || (c == '\n') || (c == '\t') || (c == XCTRL('h'))
  564.             || (c == KEY_BACKSPACE) || (c == '!') || (c == '\r')
  565.             || c == 127 || c == '+' || c == '-' || c == '\\' 
  566.             || c == '?')
  567.             c = ALT(c);
  568.             else if (isdigit(c))
  569.                     c = KEY_F (c-'0');
  570.             else if (c == ' ')
  571.             c = ESC_CHAR;
  572.             pending_keys = seq_append = NULL;
  573.             this = NULL;
  574.             return correct_key_code (c);
  575.         }
  576.         /* Did not find a match or {c} was changed in the if above,
  577.            so we have to return everything we had skipped
  578.          */
  579.         push_char (c);
  580.         pending_keys = seq_buffer;
  581.         goto pend_send;
  582.         }
  583.     }
  584.     }
  585.     this = NULL;
  586.     return correct_key_code (c);
  587. #else
  588.     return ERR;
  589. #endif /* HAVE_XVIEW */
  590. }
  591.  
  592. #ifndef HAVE_TK
  593. /* If set timeout is set, then we wait 0.1 seconds, else, we block */
  594. void try_channels (int set_timeout)
  595. {
  596.     struct timeval timeout;
  597.     static fd_set select_set;
  598.     struct timeval *timeptr;
  599.     int v;
  600.  
  601.     while (1){
  602.     FD_ZERO (&select_set);
  603.     FD_SET  (input_fd, &select_set);    /* Add stdin */
  604.     add_selects (&select_set);
  605.     
  606.     if (set_timeout){
  607.         timeout.tv_sec = 0;
  608.         timeout.tv_usec = 100000;
  609.         timeptr = &timeout;
  610.     } else
  611.         timeptr = 0;
  612.  
  613.     v = select (FD_SETSIZE, &select_set, NULL, NULL, timeptr);
  614.     if (v > 0){
  615.         check_selects (&select_set);
  616.         if (FD_ISSET (input_fd, &select_set))
  617.         return;
  618.     }
  619.     }
  620. }
  621.  
  622. #ifndef HAVE_XVIEW
  623. /* Workaround for System V Curses vt100 bug */
  624. static int getch_with_delay (void)
  625. {
  626.     int c;
  627.  
  628.     /* This routine could be used on systems without mouse support,
  629.        so we need to do the select check :-( */
  630.     while (1){
  631.     if (!pending_keys)
  632.         try_channels (0);
  633.  
  634.     /* Try to get a character */
  635.     c = get_key_code (0);
  636.     if (c != ERR)
  637.         break;
  638.     /* Failed -> wait 0.1 secs and try again */
  639.     try_channels (1);
  640.     }
  641.     /* Success -> return the character */
  642.     return c;
  643. }
  644. #endif
  645.  
  646. #ifndef HAVE_LIBGPM
  647. #define gpm_flag 0
  648. #endif
  649. #endif /* !HAVE_XVIEW */
  650.  
  651. extern int max_dirt_limit;
  652.  
  653. /* Returns a character read from stdin with appropriate interpretation */
  654. /* Also takes care of generated mouse events */
  655. /* Returns 0 if it is a mouse event */
  656. /* The current behavior is to block allways */
  657. int get_event (Gpm_Event *event, int redo_event)
  658. {
  659. #ifndef HAVE_X
  660. #define block 1
  661.     int c;
  662.     static int flag;            /* Return value from select */
  663. #ifdef HAVE_LIBGPM
  664.     static Gpm_Event ev;        /* Mouse event */
  665. #endif
  666.     struct timeval timeout;
  667.     struct timeval *time_addr = NULL;
  668.     static int dirty = 3;
  669.  
  670.     if ((dirty == 3) || is_idle ()){
  671.     refresh ();
  672.     doupdate ();
  673.     dirty = 1;
  674.     } else
  675.     dirty++;
  676.  
  677.     vfs_timeout_handler ();
  678.     
  679.     /* Ok, we use (event->x < 0) to signal that the event does not contain
  680.        a suitable position for the mouse, so we can't use show_mouse_pointer
  681.        on it.
  682.     */
  683.     if (event->x > 0){
  684.     show_mouse_pointer (event->x, event->y);
  685.     if (!redo_event)
  686.         event->x = -1;
  687.     }
  688.  
  689.     /* Repeat if using mouse */
  690.     while ((xmouse_flag || gpm_flag) && !pending_keys)
  691.     {
  692.     if (xmouse_flag || gpm_flag)
  693.     {
  694.         FD_ZERO (&select_set);
  695.         FD_SET  (input_fd, &select_set);
  696.         add_selects (&select_set);
  697.  
  698. #ifdef HAVE_LIBGPM
  699.         if (gpm_flag) {
  700.         FD_SET  (gpm_fd, &select_set);
  701.         }
  702. #endif
  703.  
  704.         if (redo_event){
  705.             timeout.tv_usec = mou_auto_repeat * 1000;
  706.         timeout.tv_sec = 0;
  707.  
  708.         time_addr = &timeout;
  709.         } else {
  710.         int seconds;
  711.         
  712.         if ((seconds = vfs_timeouts ())){
  713.             /* the timeout could be improved and actually be
  714.              * the number of seconds until the next vfs entry
  715.              * timeouts in the stamp list.
  716.              */
  717.  
  718.             timeout.tv_sec = seconds;
  719.             timeout.tv_sec = 0;
  720.             time_addr = &timeout;
  721.         } else
  722.             time_addr = NULL;
  723.         }
  724.  
  725.         if (!block){
  726.         time_addr = &timeout;
  727.         timeout.tv_sec = 0;
  728.         timeout.tv_usec = 0;
  729.         }
  730.         enable_interrupt_key ();
  731.         flag = select (FD_SETSIZE, &select_set, NULL, NULL, time_addr);
  732.         disable_interrupt_key ();
  733.         
  734.         /* select timed out: it could be for any of the following reasons:
  735.          * redo_event -> it was because of the MOU_REPEAT handler
  736.          * !block     -> we did not block in the select call
  737.          *               (this is currently unused).
  738.          * else       -> 10 second timeout to check the vfs status.
  739.          */
  740.         if (flag == 0){
  741.         if (redo_event)
  742.             return 0;
  743.         if (!block)
  744.             return -1;
  745.         vfs_timeout_handler ();
  746.         }
  747.         if (flag == -1 && errno == EINTR)
  748.         return -1;
  749.  
  750.         check_selects (&select_set);
  751.         
  752.         if (FD_ISSET (input_fd, &select_set))
  753.             break;
  754.     }
  755. #ifdef HAVE_LIBGPM
  756.     if (gpm_flag && FD_ISSET (gpm_fd, &select_set)){
  757.         if (gpm_flag){
  758.         Gpm_GetEvent (&ev);
  759.         Gpm_FitEvent (&ev);
  760.         }
  761.         *event = ev;
  762.         return 0;
  763.     }
  764. #endif
  765.     }
  766. #   ifndef HAVE_SLANG
  767.     flag = is_wintouched(stdscr);
  768.     untouchwin (stdscr);
  769. #   endif
  770.  
  771.     c = getch_with_delay ();
  772.     
  773. #   ifndef HAVE_SLANG
  774.     if (flag)
  775.         touchwin (stdscr);
  776. #   endif
  777.     
  778.     if (!c) { /* Mouse event */
  779.         xmouse_get_event (event);
  780.         return 0;
  781.     }
  782.  
  783.     return c;
  784. #else
  785.     return -1;
  786. #endif /* HAVE_XVIEW */
  787. }
  788.  
  789. /* Returns a key press, mouse events are discarded */
  790. int mi_getch ()
  791. {
  792. #ifdef HAVE_X
  793. #ifdef HAVE_TK
  794.     return tk_getch ();
  795. #else
  796.     /* FIXME: XView requires this routine to work with quote */
  797. #endif /* HAVE_TK */
  798. #else
  799.     Gpm_Event ev;
  800.     int       key;
  801.     
  802.     while ((key = get_event (&ev, 0)) == 0)
  803.     ;
  804.     return key;
  805. #endif /* HAVE_X */
  806. }
  807.  
  808. int xgetch_second (void)
  809. {
  810.     fd_set Read_FD_Set;
  811.     int c;
  812.     struct timeval timeout;
  813.  
  814.     timeout.tv_sec = ESCMODE_TIMEOUT / 1000000;
  815.     timeout.tv_usec = ESCMODE_TIMEOUT % 1000000;
  816. #ifdef BUGGY_CURSES
  817.     wtimeout(stdscr, 500);
  818. #else
  819.     nodelay (stdscr, TRUE);
  820. #endif
  821.     FD_ZERO (&Read_FD_Set);
  822.     FD_SET (input_fd, &Read_FD_Set);
  823.     select (FD_SETSIZE, &Read_FD_Set, NULL, NULL, &timeout);
  824.     c = xgetch ();
  825. #ifdef BUGGY_CURSES
  826.     notimeout (stdscr, TRUE);
  827. #else
  828.     nodelay (stdscr, FALSE);
  829. #endif
  830.     return c;
  831. }
  832.  
  833. #ifndef HAVE_X
  834. void learn_store_key (char *buffer, char **p, int c)
  835. {
  836.     if (*p - buffer > 253)
  837.         return;
  838.     if (c == ESC_CHAR) {
  839.         *(*p)++ = '\\';
  840.         *(*p)++ = 'e';
  841.     } else if (c < ' ') {
  842.         *(*p)++ = '^';
  843.         *(*p)++ = c + 'a' - 1;
  844.     } else if (c == '^') {
  845.         *(*p)++ = '^';
  846.         *(*p)++ = '^';
  847.     } else
  848.         *(*p)++ = (char) c;
  849. }
  850.  
  851. char *learn_key (void)
  852. {
  853. /* LEARN_TIMEOUT in usec */
  854. #define LEARN_TIMEOUT 200000
  855.  
  856.     fd_set Read_FD_Set;
  857.     struct timeval endtime;
  858.     struct timeval timeout;
  859.     int c = xgetch ();
  860.     char buffer [256];
  861.     char *p = buffer;
  862.     
  863.     while (c == ERR)
  864.         c = xgetch (); /* Sanity check, should be unnecessary */
  865.     learn_store_key (buffer, &p, c);
  866.     GET_TIME (endtime);
  867.     endtime.tv_usec += LEARN_TIMEOUT;
  868.     if (endtime.tv_usec > 1000000) {
  869.         endtime.tv_usec -= 1000000;
  870.         endtime.tv_sec++;
  871.     }
  872. #ifdef BUGGY_CURSES
  873.     wtimeout(stdscr, 500);
  874. #else
  875.     nodelay (stdscr, TRUE);
  876. #endif
  877.     for (;;) {
  878.         while ((c = xgetch ()) == ERR) {
  879.             GET_TIME (timeout);
  880.             timeout.tv_usec = endtime.tv_usec - timeout.tv_usec;
  881.             if (timeout.tv_usec < 0)
  882.                 timeout.tv_sec++;
  883.             timeout.tv_sec = endtime.tv_sec - timeout.tv_sec;
  884.             if (timeout.tv_sec >= 0 && timeout.tv_usec > 0) {
  885.             FD_ZERO (&Read_FD_Set);
  886.             FD_SET (input_fd, &Read_FD_Set);
  887.                 select (FD_SETSIZE, &Read_FD_Set, NULL, NULL, &timeout);
  888.             } else
  889.                 break;
  890.         }
  891.         if (c == ERR)
  892.             break;
  893.     learn_store_key (buffer, &p, c);        
  894.     }
  895. #ifdef BUGGY_CURSES
  896.     notimeout (stdscr, TRUE);
  897. #else
  898.     nodelay (stdscr, FALSE);
  899. #endif
  900.     *p = 0;
  901.     return strdup (buffer);
  902. }
  903. #endif /* !HAVE_X */
  904.  
  905. /* A function to check if we're idle.
  906.    Currently checks only for key presses.
  907.    We could also check the mouse. */
  908. int is_idle (void)
  909. {
  910.     /* Check for incoming key presses     *
  911.      * If there are any we say we're busy */
  912.  
  913.     struct fd_set select_set;
  914.     struct timeval timeout;
  915.     FD_ZERO (&select_set);
  916.     FD_SET (0, &select_set);
  917.     timeout.tv_sec = 0;
  918.     timeout.tv_usec = 0;
  919.     select (FD_SETSIZE, &select_set, 0, 0, &timeout);
  920.     return ! FD_ISSET (0, &select_set);
  921. }
  922.  
  923. int ctrl_pressed ()
  924. {
  925. #ifdef __linux__
  926.     int modifiers;
  927.  
  928.     modifiers = 6;
  929.  
  930.     if (ioctl (0, TIOCLINUX, &modifiers) < 0)
  931.     return 0;
  932.  
  933.     if (modifiers & 4)
  934.     return 1;
  935. #endif
  936.     return 0;
  937. }
  938.  
  939. #ifdef HAVE_MAD
  940. #ifndef HAVE_XVIEW
  941. void k_dispose (key_def *k)
  942. {
  943.     if (!k)
  944.     return;
  945.     k_dispose (k->child);
  946.     k_dispose (k->next);
  947.     free (k);
  948. }
  949.  
  950. void s_dispose (SelectList *sel)
  951. {
  952.     if (!sel)
  953.     return;
  954.  
  955.     s_dispose (sel->next);
  956.     free (sel);
  957. }
  958.  
  959. void done_key ()
  960. {
  961.     k_dispose (keys);
  962.     s_dispose (select_list);
  963. }
  964.  
  965. #else
  966.  
  967. void done_key () 
  968. {
  969. }
  970.  
  971. #endif /* HAVE_XVIEW */
  972. #endif /* HAVE_MAD */
  973.